package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.business.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.business.api.RemoteNoteContentService;
import cn.wolfcode.wolf2w.business.api.RemoteStrategyService;
import cn.wolfcode.wolf2w.business.api.domain.Destination;
import cn.wolfcode.wolf2w.business.api.domain.Note;
import cn.wolfcode.wolf2w.business.api.domain.NoteContent;
import cn.wolfcode.wolf2w.business.api.domain.Strategy;
import cn.wolfcode.wolf2w.business.mapper.NoteMapper;
import cn.wolfcode.wolf2w.business.query.NoteQuery;
import cn.wolfcode.wolf2w.business.service.INoteService;
import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.common.core.constant.SecurityConstants;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.core.domain.R;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 旅游日记Service业务层处理
 * 
 * @author yuhao
 * @date 2025-09-16
 */
@Service
@Transactional
public class NoteServiceImpl extends ServiceImpl<NoteMapper,Note> implements INoteService {
    @Autowired
    private RemoteDestinationService destinationService;
    @Autowired
    private RemoteNoteContentService noteContentService;
    @Autowired
    private RemoteStrategyService strategyService;
    @Autowired
    private RedisService redisService;

    @Override
    public IPage<Note> queryPage(NoteQuery qo) {
        IPage<Note> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
//        QueryWrapper<Object> wrapper = new QueryWrapper<>();
//        wrapper.orderByDesc(qo.getOrderBy());
//        if(qo.getTravelTimeType()!=-1){
//            if(qo.getTravelTimeType()==1){
//                wrapper.eq()//
//                        //
//            }
//        }

        //条件构造器
        QueryWrapper<Note> wrapper = new QueryWrapper<>();
        //分别字段尽心给判断
        //1旅游时间进行判断
            //1.1看时间travelTimeType有几个值 -1不限 1(1-2月) 2（3-4月） 3（5-6月） 4（7-8月） 5（9-10月） 6（11-12月）
            //当travelTimeType==-1，没有遍历条件
            int startMonth = 1;
            int endMonth = 1;
            if(qo.getTravelTimeType()!=-1){
                //1.2 travelTimeType==1
                if(qo.getTravelTimeType()==1){
                    //只根据月份进行查询
                    startMonth = 1;
                    endMonth = 2;
//                    wrapper.apply("month(travel_time) between {0} and {1}", startMonth, endMonth);
                }
                //1.3 travelTimeType==2
                if(qo.getTravelTimeType()==2){
                    startMonth = 3;
                    endMonth = 4;
//                    wrapper.apply("month(travel_time) between {0} and {1}", startMonth, endMonth);
                }
                //1.4 travelTimeType==3
                if(qo.getTravelTimeType()==3){
                    startMonth = 5;
                    endMonth = 6;
//                    wrapper.apply("month(travel_time) between {0} and {1}", startMonth, endMonth);
                }
                //1.5 travelTimeType==4
                if(qo.getTravelTimeType()==4){
                    startMonth = 7;
                    endMonth = 8;
//                    wrapper.apply("month(travel_time) between {0} and {1}", startMonth, endMonth);
                }
                //1.6 travelTimeType==5
                if (qo.getTravelTimeType()==5){
                    startMonth = 9;
                    endMonth = 10;
//                    wrapper.apply("month(travel_time) between {0} and {1}", startMonth, endMonth);
                }
                //1.7 travelTimeType==6
                if(qo.getTravelTimeType()==6){
                    startMonth = 11;
                    endMonth = 12;

                }
                wrapper.apply("month(travel_time) between {0} and {1}", startMonth, endMonth);
            }
        //2消费类型进行判断
            //-1(不限)
        if(qo.getConsumeType()!=-1){
            //1(1-999)
            if(qo.getConsumeType()==1){
                wrapper.between("avg_consume", 1, 999);
            }
            //2(1K-6K)
            if(qo.getConsumeType()==2){
                wrapper.between("avg_consume", 1000, 6000);
            }
            //3(6K-20K)
            if(qo.getConsumeType()==3){
                wrapper.between("avg_consume", 6000, 20000);
            }
            //4(20K以上)
            if(qo.getConsumeType()==4){
                wrapper.ge("avg_consume", 20000);
            }
        }


        //3天数进行判断
            // -1(不限)
        if(qo.getDayType()!=-1){
            //1(3天以下)
            if(qo.getDayType()==1){
                wrapper.lt("days", 3);
            }
            //2（4-7天）
            if(qo.getDayType()==2){
                wrapper.between("days", 4, 7);
            }
            //3(8-14天)
            if(qo.getDayType()==3){
                wrapper.between("days", 8, 14);
            }
            //4(15以上)
            if(qo.getDayType()==4){
                wrapper.ge("days", 15);
            }
        }

        //4根据最新判断
            //1(最新)
        if(qo.getOrderType()==1){
            wrapper.orderByDesc("create_time");
        }
            //2(最热)
        if(qo.getOrderType()==2){
            wrapper.orderByDesc("viewnum");
        }
        return baseMapper.selectPage(page, wrapper);
    }

    //添加游记
    @Override
    public void add(Note note) {
        Long userId = SecurityContextHolder.getUserId();
        System.out.println(note);
//        Destination destinationR = destinationService.destName(note.getDestId(), SecurityConstants.INNER).getData();
        Destination data = destinationService.destName(note.getDestId(), SecurityConstants.INNER).getData();
        note.setAuthorId(userId);
        note.setDestName(data.getName());
        note.setCreateTime(new Date());
        note.setUpdateTime(new Date());
        note.setViewnum(0L);
        note.setReplynum(0L);
        note.setFavornum(0L);
        note.setSharenum(0L);
        note.setThumbsupnum(0L);
        note.setStatus("0");
        baseMapper.insert(note);
    }

    @Override
    public List<Note> queryViewnumTop3(Long destId) {
         return lambdaQuery().last("limit 3").eq(Note::getDestId, destId).list();


    }

    @Override
    public Map<String, Object> collect(Long id) {
//        System.out.println("收藏。。。。。。。。。。。。");
        Long userId = SecurityContextHolder.getUserId();
        String key = RedisKeys.USER_NOTE_FAVOR.join(userId.toString());
        // 用户key是否存在
        if( ! redisService.hasKey( key) ){
            System.out.println("收藏1。。。。。。。。。。。。");
            // 初始化用户set
            Set<Long> ids=new HashSet<>();
            ids.add(-1L);
            redisService.setCacheSet(key, ids);
        }

        boolean b=false;
        String hashKey = RedisKeys.NOTE_STATIS_HASH.join(id.toString());
        System.out.println("收藏2。。。。。。。。。。。。");

        if(! redisService.isCacheSetContains(key, id)){
            // 收藏
            System.out.println("收藏3。。。。。。。。。。。。");

            redisService.incrementCacheMapValue(hashKey, "favornum", 1);
            redisService.addCacheSetValue(key, id);
            b = true;
        }else {
            // 取消收藏
            System.out.println("收藏4。。。。。。。。。。。。");
            redisService.incrementCacheMapValue(hashKey, "favornum", -1);
            redisService.addCacheSetValue(key, id);
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashKey);
        cacheMap.put("result", b);
        return cacheMap;
    }

    @Override
    public Map<String, Object> uncollect(Long id) {
        Long userId = SecurityContextHolder.getUserId();
        String key = RedisKeys.USER_NOTE_FAVOR.join(userId.toString());
        System.out.println("收藏9。。。。。。。。。。。。");

        if(  redisService.hasKey( key) ){
            System.out.println("收藏5。。。。。。。。。。。。");

            Set<Long> ids=new HashSet<>();
            ids.add(-1L);
            redisService.setCacheSet(key, ids);
        }
        boolean b=true;
        String hashKey = RedisKeys.USER_NOTE_FAVOR.join(id.toString());
        System.out.println("收藏6。。。。。。。。。。。。");

        if(redisService.isCacheSetContains(key, id)){
            System.out.println("收藏7。。。。。。。。。。。。");

            redisService.incrementCacheMapValue(hashKey, "favornum", -1);
            redisService.deleteCacheSetValue(key, id);
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashKey);
        cacheMap.put("result", b);
        System.out.println("收藏8。。。。。。。。。。。。");

        return cacheMap;


    }

    @Override
    public Map<String, Object> star(Long id) {
        Long userId = SecurityContextHolder.getUserId();
        String key = RedisKeys.USER_NOTE_THUMBSUP.join(userId.toString(), id.toString());
        Date now = new Date();
        Date end = DateUtil.getEndDate(now);
        long seconds = DateUtil.getDateBetween(now, end);
        if( ! redisService.hasKey( key)){
            redisService.setCacheObject(key, 0, seconds, TimeUnit.SECONDS);
        }
        Long ret = redisService.incrementCacheObjectValue(key, 1);
        String hashKey = RedisKeys.NOTE_STATIS_HASH.join(id.toString());
        boolean result = false;
        if(ret <= 3){
            redisService.incrementCacheMapValue(hashKey, "thumbsupnum", 1);
            result = true;
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashKey);
        cacheMap.put("result", result);
        return cacheMap;
    }




    @Override
    public void noteStar() {
//        System.out.println("开始执行定时任务");
        String hashKey = RedisKeys.NOTE_STATIS_HASH.join("*");
        Collection<String> keys = redisService.keys(hashKey);
        System.out.println("keys"+ keys);
        if(keys!=null && keys.size()>0){
            for(String key : keys){
                Map<String, Object> cacheMap = redisService.getCacheMap(key);
                lambdaUpdate().eq(Note::getId, cacheMap.get("id"))
                        .set(Note::getViewnum, cacheMap.get("viewnum"))
                        .set(Note::getReplynum, cacheMap.get("replynum"))
                        .set(Note::getFavornum, cacheMap.get("favornum"))
                        .set(Note::getSharenum, cacheMap.get("sharenum"))
                        .set(Note::getThumbsupnum, cacheMap.get("thumbsupnum"))
                        .update();
//                System.out.println("id"+cacheMap.get("id"));
            }
        }

    }

    public Map<String, Object> viewnumIncrease(Long sid) {
        String key = strategyHashInit(sid);
        //阅读量+1
        redisService.incrementCacheMapValue(key,"viewnum",1);
        //返回数据   避免出现脏数据的问题
        Map<String, Object> cacheMap = redisService.getCacheMap(key);
        return cacheMap;
    }
    //阅读量初始化
    private String strategyHashInit(Long sid) {
        String key = RedisKeys.STRATEGY_STATIS_HASH.join(sid.toString());
        if( ! redisService.hasKey(key)){  //文章第一次被访问
            //面试中需要添加布隆过滤器，如果布隆过滤器返回mysql中有数据，则从mysql中查，否则不查
            //不添加布隆过滤器会产生缓存击穿
            Strategy strategy = this.getById(sid); //到mysql中查,当第一次或则redis宕机了，redis中 就没有数据了，以mysql为准
            Map<String, Object> map = new HashMap<>();
            map.put("viewnum",Integer.valueOf(strategy.getViewnum().toString()));//redis中不能long类型的数据进行++，所以要转成int
            map.put("replynum",Integer.valueOf(strategy.getReplynum().toString()));
            map.put("sharenum",Integer.valueOf(strategy.getSharenum().toString()));
            map.put("favornum",Integer.valueOf(strategy.getFavornum().toString()));
            map.put("thumbsupnum",Integer.valueOf(strategy.getThumbsupnum().toString()));
            map.put("id",strategy.getId());  //用来说明这篇攻略有这个统计数据
            redisService.setCacheMap(key,map);  //把数据放到redis中，key是前缀加sid
        }
        return key;
    }


}


